home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 7684 / 7684.xpi / resources / fmStation.js < prev    next >
Text File  |  2009-11-20  |  11KB  |  334 lines

  1. /**
  2.  * Copyright (c) 2008, Jose Enrique Bolanos, Jorge Villalobos
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions are met:
  7.  *
  8.  *  * Redistributions of source code must retain the above copyright notice,
  9.  *    this list of conditions and the following disclaimer.
  10.  *  * Redistributions in binary form must reproduce the above copyright notice,
  11.  *    this list of conditions and the following disclaimer in the documentation
  12.  *    and/or other materials provided with the distribution.
  13.  *  * Neither the name of Jose Enrique Bolanos, Jorge Villalobos nor the names
  14.  *    of its contributors may be used to endorse or promote products derived
  15.  *    from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
  21.  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  22.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  23.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  24.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  25.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  26.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  **/
  29.  
  30. var EXPORTED_SYMBOLS = [];
  31.  
  32. const Cc = Components.classes;
  33. const Ci = Components.interfaces;
  34. const Ce = Components.Exception;
  35.  
  36. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  37. Components.utils.import("resource://firefm/fmCommon.js");
  38. Components.utils.import("resource://firefm/fmEntities.js");
  39. Components.utils.import("resource://firefm/fmPlaylist.js");
  40. Components.utils.import("resource://firefm/fmPlayer.js");
  41. Components.utils.import("resource://firefm/fmRemote.js");
  42. Components.utils.import("resource://firefm/fmLogin.js");
  43.  
  44. // The topic that indicates the application is about to quit.
  45. const TOPIC_QUIT_APPLICATION = "quit-application";
  46.  
  47. /**
  48.  * Handles station-related operations, namely picking a station and starting
  49.  * playback.
  50.  */
  51. FireFM.Station = {
  52.   // Topic notifications sent from this object.
  53.   get TOPIC_STATION_SET() { return "firefm-station-set"; },
  54.   get TOPIC_STATION_SEARCHING() { return "firefm-station-searching"; },
  55.   get TOPIC_STATION_LOADING() { return "firefm-station-loading"; },
  56.   get TOPIC_STATION_OPENING() { return "firefm-station-opening"; },
  57.   get TOPIC_STATION_STOPPING() { return "firefm-station-stopping"; },
  58.   get TOPIC_STATION_ERROR() { return "firefm-station-error"; },
  59.  
  60.   // Station errors.
  61.   get ERROR_NOT_FOUND() { return 0; },
  62.   get ERROR_INVALID_STATION() { return 1; },
  63.   get ERROR_COMMUNICATION_FAILED() { return 2; },
  64.   get ERROR_NO_CONTENT() { return 3; },
  65.   get ERROR_NO_FREE_PLAYS() { return 4; },
  66.   get ERROR_NO_SUBSCRIPTION() { return 5; },
  67.   get ERROR_SERVICE_OFFLINE() { return 6; },
  68.  
  69.   // station types.
  70.   get TYPE_ARTIST() { return 0; },
  71.   get TYPE_RECOMMENDED() { return 1; },
  72.   get TYPE_USER() { return 2; },
  73.   get TYPE_TAG() { return 3; },
  74.   get TYPE_NEIGHBORHOOD() { return 4; },
  75.   get TYPE_LOVED() { return 5; },
  76.  
  77.   /* Logger for this object. */
  78.   _logger : null,
  79.   /* The StationInfo object that represents the current station. */
  80.   _currentStation : null,
  81.   /* Flag that indicates that a station is being searched for. */
  82.   _isSearchingStation : false,
  83.   /* Flag that indicates that a station is being loaded. */
  84.   _isLoadingStation : false,
  85.  
  86.   /**
  87.    * Initializes this object.
  88.    */
  89.   init : function() {
  90.     this._logger = FireFM.getLogger("FireFM.Station");
  91.     this._logger.debug("init");
  92.     FireFM.obsService.addObserver(this, TOPIC_QUIT_APPLICATION, false);
  93.   },
  94.  
  95.   /**
  96.    * Gets the current (or last played) station.
  97.    * @return the current (or last played) station.
  98.    */
  99.   get station() {
  100.     this._logger.debug("[getter] station");
  101.  
  102.     return this._currentStation;
  103.   },
  104.  
  105.   /**
  106.    * Sets the station with the given type and id.
  107.    * @param aStationId the id of the station to set.
  108.    * @param aStationType the type of station.
  109.    */
  110.   setStation : function(aStationId, aStationType) {
  111.     this._logger.debug("setStation");
  112.  
  113.     if ((null == aStationId) || (this.TYPE_ARTIST > aStationType) ||
  114.         (this.TYPE_LOVED < aStationType) ||
  115.         (((this.TYPE_RECOMMENDED == aStationType) ||
  116.           (this.TYPE_NEIGHBORHOOD == aStationType) ||
  117.           (this.TYPE_LOVED == aStationType)) &&
  118.          (aStationId != FireFM.Login.userName))) {
  119.       this._logger.error(
  120.         "setStation. Error setting station. Station id: " + aStationId +
  121.         ", station type: " + aStationType);
  122.       FireFM.obsService.notifyObservers(
  123.         null, this.TOPIC_STATION_ERROR, this.ERROR_INVALID_STATION);
  124.     } else {
  125.       this._currentStation =
  126.         new FireFM.StationInfo(aStationId, aStationType);
  127.       FireFM.obsService.notifyObservers(
  128.         this._currentStation, this.TOPIC_STATION_SET, null);
  129.     }
  130.   },
  131.  
  132.   /**
  133.    * Indicates that a station is being loaded.
  134.    * @return true if a station is being loaded, false otherwise.
  135.    */
  136.   get isLoadingStation() {
  137.     this._logger.debug("[getter] isLoadingStation");
  138.  
  139.     return this._isLoadingStation;
  140.   },
  141.  
  142.   /**
  143.    * Indicates that a station is being searched for.
  144.    * @return true if a station is being  searched for, false otherwise.
  145.    */
  146.   get isSearchingStation() {
  147.     this._logger.debug("[getter] isSearchingStation");
  148.  
  149.     return this._isSearchingStation;
  150.   },
  151.  
  152.   /**
  153.    * Verifies the station information entered by the user against Last.FM.
  154.    * @param aId the ID of the station.
  155.    * @param aType the type of the station.
  156.    * @param aCallback the callback function provided by the caller.
  157.    */
  158.   verifyStation : function(aId, aType, aCallback) {
  159.     this._logger.debug("verifyStation");
  160.  
  161.     let that = this;
  162.  
  163.     this._isSearchingStation = true;
  164.     FireFM.obsService.notifyObservers(
  165.       null, FireFM.Station.TOPIC_STATION_SEARCHING, aId);
  166.  
  167.     switch (aType) {
  168.       case this.TYPE_ARTIST:
  169.         FireFM.Remote.artistSearch(
  170.           aId,
  171.           function(aResult) {
  172.             that._verifyStationLoad(aResult, aType, aCallback); });
  173.         break;
  174.       case this.TYPE_TAG:
  175.         FireFM.Remote.tagSearch(
  176.           aId,
  177.           function(aResult) {
  178.             that._verifyStationLoad(aResult, aType, aCallback); });
  179.         break;
  180.       default:
  181.         // we don't verify the other stations, so we call the handler directly.
  182.         this._verifyStationLoad(
  183.           { success : true, result : aId }, aType, aCallback);
  184.         break;
  185.     }
  186.   },
  187.  
  188.   /**
  189.    * Load handler for the verify station request.
  190.    * @param aResult the resulting object from the request. See
  191.    * FireFM.Remote.verifyStation for more information.
  192.    * @param aType the type of station to load.
  193.    * @param aCallback the callback function provided by the caller.
  194.    */
  195.   _verifyStationLoad : function(aResult, aType, aCallback) {
  196.     this._logger.debug("_verifyStationLoad");
  197.  
  198.     if (this._isSearchingStation) {
  199.       this._isSearchingStation = false;
  200.       aCallback(aResult, aType);
  201.     }
  202.   },
  203.  
  204.   /**
  205.    * Plays the currently selected station.
  206.    */
  207.   play : function() {
  208.     this._logger.debug("play");
  209.  
  210.     if (null == this._currentStation) {
  211.       this._logger.error("play. No station selected!");
  212.       throw new Ce("No station selected when play was called.");
  213.     }
  214.  
  215.     this.stop();
  216.     this._isLoadingStation = true;
  217.     FireFM.obsService.notifyObservers(
  218.       this._currentStation, this.TOPIC_STATION_LOADING, null);
  219.     // TODO: do getPlaylist only when we know we have the station tuned already.
  220.     FireFM.Remote.tuneRadio();
  221.   },
  222.  
  223.   /**
  224.    * Stops playback on the current station.
  225.    */
  226.   stop : function() {
  227.     this._logger.debug("stop");
  228.     FireFM.obsService.notifyObservers(
  229.       this._currentStation, this.TOPIC_STATION_STOPPING, null);
  230.  
  231.     try {
  232.       this._isLoadingStation = false;
  233.       this._isSearchingStation = false;
  234.       FireFM.Player.stop();
  235.       FireFM.Remote.scrobbleTrack();
  236.       FireFM.Playlist.clearPlaylist();
  237.     } catch (e) {
  238.       this._logger.error("stop. Error trying to stop player:\n" + e);
  239.     }
  240.   },
  241.  
  242.   /**
  243.    * Skips to the next track in the playlist.
  244.    */
  245.   skip : function() {
  246.     this._logger.debug("skip");
  247.  
  248.     FireFM.Remote.skipTrack();
  249.  
  250.     if (FireFM.Playlist.hasMoreTracks()) {
  251.       try {
  252.         FireFM.Player.play();
  253.       } catch (e) {
  254.         this._logger.error("skip. Error playing next track:\n" + e);
  255.       }
  256.     } else {
  257.       try {
  258.         this.stop();
  259.         this.play();
  260.       } catch (e) {
  261.         this._logger.error("skip. Error restarting station:\n" + e);
  262.       }
  263.     }
  264.   },
  265.  
  266.   /**
  267.    * Load callback handler for the get playlist request.
  268.    * @param aDocument the XML document that contains the playlist. Can be null
  269.    * in case of error.
  270.    */
  271.   loadPlaylist : function(aDocument) {
  272.     this._logger.debug("loadPlaylist");
  273.  
  274.     if (this._isLoadingStation) {
  275.       this._isLoadingStation = false;
  276.  
  277.       if (null != aDocument) {
  278.         try {
  279.           try {
  280.             FireFM.Playlist.setNewPlaylist(aDocument);
  281.           } catch (e) {
  282.             this._logger.error(
  283.               "loadPlaylist. Invalid data received: " + aDocument +
  284.               "\n Error: " + e);
  285.             FireFM.obsService.notifyObservers(
  286.               null, this.TOPIC_STATION_ERROR, this.ERROR_NO_CONTENT);
  287.           }
  288.  
  289.           if (FireFM.Playlist.hasMoreTracks()) {
  290.             FireFM.obsService.notifyObservers(
  291.               this._currentStation, this.TOPIC_STATION_OPENING, null);
  292.             FireFM.Player.play();
  293.           } else {
  294.             FireFM.obsService.notifyObservers(
  295.               null, this.TOPIC_STATION_ERROR, this.ERROR_NO_CONTENT);
  296.           }
  297.         } catch (e) {
  298.           this._logger.error(
  299.             "loadPlaylist. Error playing playlist.\n Error: " + e);
  300.           FireFM.obsService.notifyObservers(
  301.             null, this.TOPIC_STATION_ERROR, this.ERROR_COMMUNICATION_FAILED);
  302.         }
  303.       } else {
  304.         FireFM.obsService.notifyObservers(
  305.           this._currentStation, this.TOPIC_STATION_ERROR,
  306.           this.ERROR_NO_CONTENT);
  307.       }
  308.     } else {
  309.       this._logger.warn("loadPlaylist. Load cancelled by user.");
  310.       FireFM.Playlist.clearPlaylist();
  311.     }
  312.   },
  313.  
  314.   /**
  315.    * Observes notifications of cookie and track activity.
  316.    * @param aSubject The object that experienced the change.
  317.    * @param aTopic The topic being observed.
  318.    * @param aData The data related to the change.
  319.    */
  320.   observe : function(aSubject, aTopic, aData) {
  321.     if (TOPIC_QUIT_APPLICATION == aTopic) {
  322.       this._logger.debug("observe. The application is about to quit.");
  323.       this.stop();
  324.     }
  325.   }
  326. };
  327.  
  328. /**
  329.  * FireFM.Station constructor.
  330.  */
  331. (function() {
  332.   this.init();
  333. }).apply(FireFM.Station);
  334.